In [1]:
    
include("dual.jl")
    
    Out[1]:
Let's implement a very basic version of dual numbers (done much better here. A dual number is written as $$a + b\epsilon$$ where $a$ and $b$ are real numbers and $$\epsilon^2 = 0$$ Basically, a dual number encodes both a point in space and a local derivative.
To start, we'll assume that dual numbers are only a generalization of Float64.
We will also define (though it's not rigorously true) that these numbers are subtypes of Real. That way, any function that admits a Real will also admit a Dual.
Dual <: Real for convenience, not math. We want Duals to go where Reals are allowed.immutable we could have used type. immutable means that we cannot change these numbers, but as a consequence, they can be stack-allocated and faster.Any.) In contrast to function arguments, we absolutely want these to be concrete, if possible, since abstract fields lead to a performance hit.
In [2]:
    
aa = Dual(1, 2)  # note implicit conversion to Float64
    
    Out[2]:
In [3]:
    
fieldnames(aa)
    
    Out[3]:
In [4]:
    
aa.val, aa.adj
    
    Out[4]:
In [5]:
    
aa
    
    Out[5]:
To make Dual "just work" we need to define how to upconvert other numbers to it. We can do this by extending convert.
Notes:
::)Type{Dual}; Type{T} is a type of which the DataType T is the only member (that is, we're specifying tha that the call looked like convert(Dual, 4.) or similarx can be any real numberDual; Real numbers just have adj = 0.
In [6]:
    
convert(Dual, 5)
    
    Out[6]:
We also need to define a promotion rule. Promotion rules stipulate what happens when we need to find a type "big enough" to hold two things (for addition, comparison, etc.)
With promotion and conversion defined, we only need to add arithmetic for Duals. Other arithmetic operations automatically promote as needed.
In [7]:
    
Dual(5, 2) - Dual(3, 1)
    
    Out[7]:
In [8]:
    
Dual(5, 2)/Dual(3, 1)
    
    Out[8]:
Now watch what we get for free:
In [9]:
    
5 + Dual(3, 2), Dual(3, 2) + 2
    
    Out[9]:
In [10]:
    
4.5/Dual(1, 1)
    
    Out[10]:
In [11]:
    
Array{Dual}(rand(5, 5))
    
    Out[11]:
In [12]:
    
A = rand(5, 5) + Dual(0, 1) * Array{Dual}(rand(5, 5))
    
    Out[12]:
In [13]:
    
A * rand(5)
    
    Out[13]:
In [14]:
    
minimum(A), maximum(A)
    
    Out[14]:
In [15]:
    
Dual(1, 1) <= Dual(1, 0.8)
    
    Out[15]:
In [16]:
    
A \ rand(5)
    
    Out[16]:
In [17]:
    
function foo(x, y)
    log(x + y) - y
end
    
    Out[17]:
In [18]:
    
foo(Dual(1, 1), 2)
    
    Out[18]:
In [19]:
    
foo(1, Dual(2, 1))
    
    Out[19]:
In [ ]: